import java.rmi.RemoteException;
import java.util.Queue;
import java.util.LinkedList;


public class ServerObject_Impl implements ServerObject {
	private int id;
	private Object ob;	//a local copy of the object.
	private Queue<Client_itf> readers = new LinkedList<Client_itf>();
	private Client_itf writer;
	
	
	public ServerObject_Impl(int id, Object ob){
		this.id = id;
		this.ob = ob;
	}
	
	@Override
	public synchronized Object lock_read(Client_itf client){
		System.out.println("Server.lock_read()");
		if(ob == null)
			System.out.println("The object was null in the beginning! :-(");
		else
			System.out.println("The object WAS THERE in the beginning!");
		if(writer == null){	//NL->RLT, RLT->RLT
			readers.add(client);
			return ob;
	
		}else{	//WLT->RLT
			try {
				Object obLocal = writer.reduce_lock(id);
				ob = obLocal;
				
				readers.add(writer);

			}catch(java.rmi.ConnectException ce){
				System.err.println("Couldn't contact the writer for reduce_lock() for: " + id + "! (WLT->RLT)");
				//TODO: Put the object's state to RLT (remove the old writer, don't add it as a reader (cuzz it's dead)). Should be done for each of the three "Couldn't contact the..." errors.

			}catch(RemoteException e){
				System.err.println("Couldn't reduce lock for: " + id + " (WLT->RLT)");
				e.printStackTrace();
				if(id==0)
					System.exit(Integer.MIN_VALUE);
				else
					System.exit(-id);
			}
			
			readers.add(client);
			writer = null;
			
			
			if(ob == null)
				System.out.println("The object was null in the end! :(");
			else
				System.out.println("The object WAS THERE in the end (gonna return a non-null object.)!");
			
			return ob;
		}
	}

	@Override
	public synchronized Object lock_write(Client_itf client) {
		System.out.println("Server.lock_write()");
		if(readers.isEmpty())
			if(writer==null){	//NL->WLT
				writer = client;
				return ob;
				
			}else{	//WLT->WLT
				try{
					ob = writer.invalidate_writer(id);	//TODO: an efficiency matter - don't invalidate if client == writer.
					
				}catch(java.rmi.ConnectException ce){
					System.err.println("Couldn't contact the writer for invalidate_writer() for: " + id + "! (WLT->WLT)");
					
				}catch(RemoteException e){
					System.err.println("Couldn't invalidate writer for: " + id + " (WLT->WLT");
					e.printStackTrace();
					if(id==0)
						System.exit(Integer.MIN_VALUE);
					else
						System.exit(-id);
				}
				
				writer = client;
				return ob;
			}
		
		else{	//RLT->WLT
			writer = client;
			//invalidate all the readers, TODO: preferably in an asynchronous manner, with a cyclic barrier in the end.
			Client_itf reader = readers.poll();
			while(reader != null){
				try {
					if(reader != writer)	//more efficient not to invalidate THE reader who is passing on to writing
						reader.invalidate_reader(id);
					
				}catch(java.rmi.ConnectException ce){
					System.err.println("Couldn't contact the reader for invalidate_reader() for: " + id + "! (RLT->WLT)");
					
				} catch (RemoteException e) {
					System.err.println("Couldn't invalidate reader for: " + id + " (RLT->WLT)");
					e.printStackTrace();
					if(id==0)
						System.exit(Integer.MIN_VALUE);
					else
						System.exit(-id);
				}
				
				reader = readers.poll();
			}
			System.out.println("Lock_write done");	
			return ob;
		}
	}

	
	public Descriptor getDescriptor(){
		return new Descriptor(id, ob);
	}
}
